package com.example.springbootdemo2023.bus.account.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.example.springbootdemo2023.bus.account.dto.Account;
import com.example.springbootdemo2023.bus.account.dto.ChangePwdAccountDTO;
import com.example.springbootdemo2023.bus.account.dto.LoginDto;
import com.example.springbootdemo2023.bus.account.dto.UserSysDataDTO;
import com.example.springbootdemo2023.bus.account.mapper.AccountMapper;
import com.example.springbootdemo2023.bus.account.service.IAccountService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springbootdemo2023.bus.menu.dto.Menu;
import com.example.springbootdemo2023.bus.role.dto.Role;
import com.example.springbootdemo2023.bus.staff.dto.Staff;
import com.example.springbootdemo2023.bus.staff.service.IStaffService;
import com.example.springbootdemo2023.core.dto.MyPageBand;
import com.example.springbootdemo2023.core.dto.MyPager;
import com.example.springbootdemo2023.core.dto.MyResult;
import com.example.springbootdemo2023.core.util.MyJWTUtil;
import com.example.springbootdemo2023.core.util.MyRedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author GaoJingBo
 * @since 2023-03-17
 */
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements IAccountService {


    @Autowired
    private MyRedisUtil redisUtil;

    @Value("${springDemo.errCount}")
    private Integer errCount; // 通过配置文件注入

    @Resource(name = "staffServiceImpl")
    private IStaffService staffService;

    @Override
    public MyResult doLogin(LoginDto dto) {

        MyResult result = new MyResult();

        QueryWrapper<Account> loginWrapper = new QueryWrapper<>();
        loginWrapper.eq("userName",dto.getUserName());
        // 数据库中存储的就是md5密文，判断密码是否相同要将用户填写的密码也通过md5加密比较密文是否相同
        loginWrapper.eq("acpwd", DigestUtil.md5Hex(dto.getPwd()));

        Account count = this.getOne(loginWrapper);

        if(count!=null){
            result.setMsg("登录成功！");

            //登录成功需要放置两个信息
            // user: 登录成功的当前用户实体信息
            // token: jwt令牌
            Map<String,Object> res = new HashMap<>();
            res.put("user",count);
            res.put("token",MyJWTUtil.getToken(dto.getUserName()));

            result.setData(res);

        }else{ // 用户名或密码错误

            // 根据用户名查询用户信息
            QueryWrapper<Account> updateWrapper = new QueryWrapper<>();
            updateWrapper.eq("userName",dto.getUserName());

            Account updateSelectDO = this.getOne(updateWrapper);

            if(updateSelectDO.getState() == 2){// 用户已锁定

                result.setMsg("该用户已锁定，无法登录！");
                result.setCode("9999");
                return result;
            }

            // 修改用户信息对象
            Account updateDO = new Account();
            updateDO.setAccountID(updateSelectDO.getAccountID()); // 设置了更新条件，以用户id来进行更新

            // 对用户的输入错误次数进行记录
            int nowErrCount = updateSelectDO.getCwCount()+1;

            // 剩余几次尝试的机会 0
            int lessCount = this.errCount - nowErrCount;
            if(lessCount==0){ // 机会用完。账号锁定
                result.setMsg("用户名或密码错误，账号锁定请联系管理员！");
                result.setCode("9999");
                updateDO.setState(2); // 设置账号锁定
            }else if(lessCount<=4){// 开启行为验证码

                // 保存当前用户需要开启行为验证码的记录
                redisUtil.set("xwyz#"+dto.getUserName(),1,60 * 10);
                result.setMsg("用户名或密码错误,还剩【"+lessCount+"】次尝试机会！");
                result.setCode("9999");
                updateDO.setCwCount(nowErrCount);
            }else{
                result.setMsg("用户名或密码错误,还剩【"+lessCount+"】次尝试机会！");
                result.setCode("9999");
                updateDO.setCwCount(nowErrCount);
            }

            // 更新当前用户的密码错误记录信息
            boolean b = this.updateById(updateDO);
            if(!b){
                result.setMsg("登录接口异常！");
                result.setCode("9999");
            }

        }

        return result;
    }

    @Override
    public MyResult unLockAccounts(String accountIDs) {

        MyResult result = new MyResult();

         // 1. 传递的id进行拆分
        List<String> idList = Arrays.asList(accountIDs.split(","));

        // 校验传递的id对应的用户是否都是锁定状态
        // 查询对应id的所有用户，判断状态 state字段值是否为2
        QueryWrapper<Account> selectWrapper = new QueryWrapper<>();
        selectWrapper.in("accountID",idList);

        String errMsg = "";

        List<Account> list = this.list(selectWrapper);
        for(Account cc : list){
            if(cc.getState()==1){// 出现了选择未被锁定的账号进行解锁操作
                errMsg += cc.getUserName()+",";
            }
        }

        if(!errMsg.equals("")){// 有错误
            result.setMsg("【"+errMsg+"】用户未锁定请勿进行解除锁定操作！");
            result.setCode("9999");
            return  result;
        }


        // 2. 将对应id的用户state设置为1，cwCount设置为0
        Account accountUpdateDO = new Account();
        accountUpdateDO.setState(1);
        accountUpdateDO.setCwCount(0);

        // 更新的条件
        QueryWrapper<Account> updateWrapper = new QueryWrapper<>();
        updateWrapper.in("accountID",idList); // where accountID in （集合）

        boolean update = this.update(accountUpdateDO, updateWrapper);

        if(update){
            result.setMsg("用户解除锁定操作成功！");
            return  result;
        }else{
            result.setMsg("用户解除锁定操作错误！");
            result.setCode("9999");
            return  result;
        }
    }

    @Override
    public MyResult changeAccountPwd(ChangePwdAccountDTO dto) {

        MyResult result = new MyResult();

        Account accountDO = this.getById(dto.getAccountID());

        // 1. 先验证旧密码是否正确
        if(!DigestUtil.md5Hex(dto.getOldPwd()).equals(accountDO.getAcpwd())){// 旧密码输入错误
            result.setMsg("旧密码输入错误！");
            result.setCode("9999");
            return  result;
        }

        accountDO.setAcpwd(DigestUtil.md5Hex(dto.getNewPwd()));

        boolean isOk = this.updateById(accountDO);

        if(isOk){
            result.setMsg("密码修改成功！");
            return  result;
        }else{
            result.setMsg("密码修改错误！");
            result.setCode("9999");
            return  result;
        }
    }

    @Override
    public MyPager<Account> myPage(Account account, MyPageBand pageBand) {

        // 想要访问当前Account 对应的mybatis-plus的mapper层对象
        AccountMapper mapper = this.getBaseMapper();

        // 定义一个自定义分页接口
        IPage<Account> pages = mapper.myPage(PageDTO.of(pageBand.getPage(),pageBand.getSize()),account);

        // 根据分页的结果封装返回数据
        MyPager<Account> pager = new MyPager<>();
        pager.setTotal(pages.getTotal());
        pager.setPage(pageBand.getPage());
        pager.setPageSize(pageBand.getSize());
        pager.setRows(pages.getRecords());

        return pager;
    }

    @Override
    public MyResult getUserAllSysData(String accountID) {
        MyResult result = new MyResult();

        UserSysDataDTO dto = new UserSysDataDTO();

        AccountMapper userMapper = getBaseMapper();

        //1.查询用户数据
        Account account = userMapper.selectById(accountID);
        dto.setUser(account);

        //2.查询角色数据
        Role role = userMapper.getRoleData(accountID);
        dto.setRole(role);

        //3.查询菜单数据
        List<Menu> menuList = userMapper.getRoleMenuData(accountID);
        dto.setRoleMenu(menuList);

        //4.查询员工数据
        QueryWrapper<Staff> staffQueryWrapper = new QueryWrapper<>();
        staffQueryWrapper.eq("accountID",accountID);

        Staff staff = staffService.getOne(staffQueryWrapper);
        dto.setStaff(staff);

        if(account!=null){
            result.setMsg("查询成功！");
            result.setData(dto);
        }else{
            result.setMsg("查询失败！");
            result.setCode("9999");
        }


        return result;
    }

    @Override
    public MyResult getNotGranteStaffAccountList(Account dto) {

        MyResult result = new MyResult();

        AccountMapper accountMapper = getBaseMapper();

        List<Account> accounts = accountMapper.getNotGranteStaffAccountList(dto);

        result.setData(accounts);

        return result;
    }
}
